সিঙ্ক্রোনাইজেশন (Synchronization) হলো Java তে একাধিক থ্রেডের মধ্যে ডেটা অ্যাক্সেস ও পরিবর্তনের নিয়ন্ত্রণ করার একটি প্রক্রিয়া, যাতে থ্রেডগুলো সমন্বিতভাবে (সিঙ্ক্রোনাইজড) কাজ করতে পারে। সিঙ্ক্রোনাইজেশন বিশেষত তখন ব্যবহৃত হয় যখন একাধিক থ্রেড একই রিসোর্সে (যেমন একটি ভ্যারিয়েবল বা অবজেক্ট) একযোগে অ্যাক্সেস বা পরিবর্তন করার চেষ্টা করে। এটি ডেটা ইনকনসিস্টেন্সি বা অনির্দিষ্ট ফলাফল থেকে প্রোগ্রামকে রক্ষা করতে সহায়ক।
সিঙ্ক্রোনাইজেশন কেন প্রয়োজন?
- ডেটা ইনকনসিস্টেন্সি এড়াতে: যখন একাধিক থ্রেড একসাথে একই ডেটায় কাজ করে, তখন ডেটা ইনকনসিস্টেন্ট হতে পারে। সিঙ্ক্রোনাইজেশন নিশ্চিত করে যে একটি থ্রেড ডেটা পরিবর্তন সম্পূর্ণ না করা পর্যন্ত অন্য কোনো থ্রেড সেই ডেটা অ্যাক্সেস করতে পারবে না।
- ডেডলক এবং রেস কন্ডিশন এড়াতে: একাধিক থ্রেডের মধ্যে রিসোর্স ব্যবহারের সংঘর্ষ এড়ানো যায়, যা ডেডলক এবং রেস কন্ডিশনের সমস্যা এড়াতে সহায়ক।
- ডেটা সুরক্ষা: সিঙ্ক্রোনাইজেশন ব্যবহারে ডেটা সুরক্ষিত থাকে, বিশেষত সংবেদনশীল তথ্য ব্যবহারের সময়।
সিঙ্ক্রোনাইজেশন কিভাবে কাজ করে?
Java তে synchronized কীওয়ার্ড ব্যবহার করে সিঙ্ক্রোনাইজেশন করা হয়। এটি মূলত মেথড এবং ব্লক এই দুইভাবে ব্যবহার করা যায়।
- সিঙ্ক্রোনাইজড মেথড (Synchronized Method): সম্পূর্ণ মেথডকে সিঙ্ক্রোনাইজড করা হয়।
- সিঙ্ক্রোনাইজড ব্লক (Synchronized Block): মেথডের একটি নির্দিষ্ট অংশ সিঙ্ক্রোনাইজড করা হয়।
সিঙ্ক্রোনাইজড মেথড উদাহরণ
class Counter {
private int count = 0;
// synchronized মেথড
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class SynchronizedMethodExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
// দুইটি থ্রেড তৈরি এবং চালু করা
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count: " + counter.getCount());
}
}
আউটপুট:
Final Count: 2000
ব্যাখ্যা:
increment()মেথডেsynchronizedকীওয়ার্ড ব্যবহার করা হয়েছে, ফলে একাধিক থ্রেড এই মেথডে একযোগে প্রবেশ করতে পারবে না।t1এবংt2থ্রেড একই অবজেক্টেরincrement()মেথডে কাজ করার কারণে, এটি সঠিক ফলাফল প্রদান করে।
সিঙ্ক্রোনাইজড ব্লক উদাহরণ
কখনও কখনও সম্পূর্ণ মেথড সিঙ্ক্রোনাইজ করা অপ্রয়োজনীয় হতে পারে, তখন নির্দিষ্ট ব্লক সিঙ্ক্রোনাইজ করা হয়।
class Counter {
private int count = 0;
public void increment() {
synchronized (this) {
count++;
}
}
public int getCount() {
return count;
}
}
public class SynchronizedBlockExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count: " + counter.getCount());
}
}
ব্যাখ্যা:
synchronized (this)ব্লকের মাধ্যমে কেবলcount++অপারেশনটি সিঙ্ক্রোনাইজ করা হয়েছে।- এটি নিশ্চিত করে যে শুধুমাত্র
countপরিবর্তনের সময় থ্রেডগুলো সমন্বিতভাবে কাজ করবে।
স্ট্যাটিক মেথডে সিঙ্ক্রোনাইজেশন
স্ট্যাটিক মেথডে সিঙ্ক্রোনাইজেশন করতে synchronized কীওয়ার্ড ব্যবহার করা হয়, তবে এটি this অবজেক্টের পরিবর্তে ক্লাস অবজেক্টে কাজ করে।
class StaticCounter {
private static int count = 0;
public static synchronized void increment() {
count++;
}
public static int getCount() {
return count;
}
}
ব্যাখ্যা:
- স্ট্যাটিক মেথডে
synchronizedব্যবহার করলে এটি ক্লাস অবজেক্টে সিঙ্ক্রোনাইজড হয়, ফলে স্ট্যাটিক ভেরিয়েবল সঠিকভাবে আপডেট হয়।
সিঙ্ক্রোনাইজেশন সম্পর্কিত গুরুত্বপূর্ণ বিষয়
- মনিটর লক (Monitor Lock): যখন কোনো থ্রেড সিঙ্ক্রোনাইজড মেথড বা ব্লকে প্রবেশ করে, তখন সে মনিটর লক (Monitor Lock) অর্জন করে। লক না পেলে থ্রেড অপেক্ষা করে।
- ডেডলক (Deadlock): যদি দুটি থ্রেড একে অপরের জন্য অপেক্ষা করে, তাহলে এটি ডেডলক সৃষ্টি করে। ডেডলক এড়ানোর জন্য সঠিকভাবে সিঙ্ক্রোনাইজেশন করা গুরুত্বপূর্ণ।
- পারফরম্যান্সে প্রভাব: সিঙ্ক্রোনাইজড ব্লক বা মেথড থ্রেডের একসঙ্গে প্রবেশের সুযোগ কমায়, ফলে পারফরম্যান্সে কিছুটা প্রভাব ফেলে। তাই প্রয়োজন ছাড়া সিঙ্ক্রোনাইজেশন ব্যবহার এড়ানো উচিত।
সিঙ্ক্রোনাইজেশন সংক্রান্ত সুবিধা এবং সীমাবদ্ধতা
সুবিধা
- ডেটা সুরক্ষা নিশ্চিত: একাধিক থ্রেডের মধ্যে সমন্বিত ডেটা অ্যাক্সেস নিশ্চিত করে।
- রেস কন্ডিশন প্রতিরোধ: রেস কন্ডিশনের কারণে ডেটা ইনকনসিস্টেন্সি প্রতিরোধ করে।
- একযোগে অ্যাক্সেস নিয়ন্ত্রণ: একাধিক থ্রেডের সমন্বিত কাজ নিশ্চিত করে।
সীমাবদ্ধতা
- পারফরম্যান্সে প্রভাব: অতিরিক্ত সিঙ্ক্রোনাইজেশন ব্যবহারে প্রোগ্রামের গতি কমে যেতে পারে।
- ডেডলক ঝুঁকি: সঠিকভাবে সিঙ্ক্রোনাইজ করা না হলে ডেডলক হতে পারে, যা থ্রেডগুলিকে অনির্দিষ্টকালের জন্য আটকে রাখতে পারে।
- কোড জটিলতা: সিঙ্ক্রোনাইজেশন ব্যবহারে কোড জটিল হতে পারে এবং ডিবাগিং কঠিন হতে পারে।
সারসংক্ষেপ
- সিঙ্ক্রোনাইজেশন হলো একাধিক থ্রেডের মধ্যে ডেটা অ্যাক্সেস ও পরিবর্তনের নিয়ন্ত্রণ, যা ডেটা ইনকনসিস্টেন্সি প্রতিরোধে সহায়ক।
- Java তে
synchronizedকীওয়ার্ড ব্যবহার করে মেথড বা ব্লককে সিঙ্ক্রোনাইজ করা যায়। - সঠিকভাবে সিঙ্ক্রোনাইজেশন ব্যবহারে ডেটা সুরক্ষা ও সঠিকতা নিশ্চিত হয়, তবে এটি ব্যবহারে পারফরম্যান্স এবং ডেডলকের মতো সমস্যা হতে পারে।
Java প্রোগ্রামিংয়ে সিঙ্ক্রোনাইজেশন ব্যবহার করে থ্রেড সেফটি নিশ্চিত করা যায়, যা বহুমুখী এবং জটিল প্রোগ্রামগুলোর জন্য অত্যন্ত গুরুত্বপূর্ণ।